package com.yc.sole.erp.biz;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import com.google.common.collect.Lists;
import com.yc.sole.common.constant.PubConstant;
import com.yc.sole.common.domain.StateCountResp;
import com.yc.sole.erp.dto.MoldDto;
import com.yc.sole.erp.dto.ProduceDto;
import com.yc.sole.erp.dto.ProductDto;
import com.yc.sole.erp.dto.SaleOrderDto;
import com.yc.sole.erp.enums.OrderState;
import com.yc.sole.erp.enums.ProduceSourceType;
import com.yc.sole.erp.enums.ProduceState;
import com.yc.sole.erp.exception.ErpResultEnum;
import com.yc.sole.erp.repository.*;
import com.yc.sole.erp.request.ProduceQueryReq;
import com.yc.sole.erp.request.ProduceReq;
import com.yc.sole.erp.response.ProduceResp;
import com.yc.sole.erp.response.ProductResp;
import com.yc.sole.framework.exception.BaseException;
import com.yc.sole.framework.mybatis.page.Paging;
import com.yc.sole.framework.mybatis.util.PageUtil;
import com.yc.sole.system.service.SequenceService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 服务接口实现
 *
 * @author yizuomin
 * @date 2024-01-13
 **/
@Slf4j
@Service
@RequiredArgsConstructor
public class ProduceBiz {

    private final ProduceRepository produceRepository;
    private final ProductRepository productRepository;
    private final SaleOrderRepository saleOrderRepository;
    private final SequenceService sequenceService;
    private final MoldRepository moldRepository;
    private final CustomerRepository customerRepository;

    /**
     * 新增排产
     *
     * @param produceReq
     */
    @Transactional(rollbackFor = Exception.class)
    public void saveProduce(ProduceReq produceReq) {
        // 查询模具
        MoldDto moldDto = moldRepository.selectMoldById(produceReq.getMoldId());
        if (Objects.isNull(moldDto)) {
            throw new BaseException(ErpResultEnum.MOLD_NOT_FOUND);
        }
        // 查询是否存在产品信息，不存在则新增
        ProductDto productDto = productRepository.selectByIdDetail(produceReq.getMoldId(), produceReq.getColor(), produceReq.getMaterial(), produceReq.getSize(), produceReq.getLength());
        if (Objects.isNull(productDto)) {
            productDto = productRepository.saveAndReturn(moldDto, produceReq.getColor(), produceReq.getMaterial(), produceReq.getSize(), produceReq.getLength());
        }
        ProduceDto produceDto = new ProduceDto();
        String seqNo = sequenceService.generateSeqNo(PubConstant.PRODUCTION_SEQ_KEY);
        produceDto.setProduceNo(seqNo);
        produceDto.setProduceDate(DateUtil.today());
        produceDto.setOrderId(null);
        produceDto.setProductId(productDto.getId());
        produceDto.setProductName(productDto.getProductName());
        produceDto.setCustomerId(0L);
        produceDto.setCustomerName(ProduceSourceType.INVENTORY_STOCKING.getDescription());
        produceDto.setQuantity(produceReq.getQuantity());
        produceDto.setRemainingQuantity(produceReq.getQuantity());
        produceDto.setPriority(produceReq.getPriority());
        produceDto.setProduceState(ProduceState.IN_PRODUCTION);
        produceDto.setSourceType(ProduceSourceType.INVENTORY_STOCKING);
        produceDto.setProduceEndDate(null);
        produceDto.setRemark(produceReq.getRemark());
        produceRepository.saveProduce(produceDto);
    }

    /**
     * 修改
     *
     * @param produceReq
     */
    @Transactional(rollbackFor = Exception.class)
    public void updateProduceById(ProduceReq produceReq) {
        // 查询排产
        ProduceDto produceDto = produceRepository.selectProduceById(produceReq.getId());
        if (Objects.isNull(produceDto)) {
            throw new BaseException(ErpResultEnum.PRODUCE_NOT_FOUND);
        }
        // 已完成不能修改
        if (ProduceState.FINISHED.equals(produceDto.getProduceState())) {
            throw new BaseException(ErpResultEnum.PRODUCE_COMPLETE);
        }
        ProduceDto dto = new ProduceDto();
        dto.setId(produceDto.getId());
        if (ProduceSourceType.SALE_ORDER.equals(produceDto.getSourceType())) {
            // 订单来源只能修改优先级和备注
            dto.setPriority(produceReq.getPriority());
            dto.setRemark(produceReq.getRemark());
        } else {
            // 查询模具
            MoldDto moldDto = moldRepository.selectMoldById(produceReq.getMoldId());
            if (Objects.isNull(moldDto)) {
                throw new BaseException(ErpResultEnum.MOLD_NOT_FOUND);
            }
            // 查询是否存在产品信息，不存在则新增
            ProductDto productDto = productRepository.selectByIdDetail(produceReq.getMoldId(), produceReq.getColor(), produceReq.getMaterial(), produceReq.getSize(), produceReq.getLength());
            if (Objects.isNull(productDto)) {
                productDto = productRepository.saveAndReturn(moldDto, produceReq.getColor(), produceReq.getMaterial(), produceReq.getSize(), produceReq.getLength());
            }
            int producedQuantity = produceDto.getQuantity() - produceDto.getRemainingQuantity();
            dto.setProductId(productDto.getId());
            dto.setQuantity(produceReq.getQuantity());
            dto.setPriority(produceReq.getPriority());
            dto.setRemark(produceReq.getRemark());
            dto.setRemainingQuantity(produceReq.getQuantity() - producedQuantity);
        }
        produceRepository.updateProduceById(dto);
    }

    /**
     * 删除
     *
     * @param ids
     */
    @Transactional(rollbackFor = Exception.class)
    public void deleteProduce(Collection<Long> ids) {
        List<ProduceDto> produceDtoList = produceRepository.selectProduceByIds(ids);
        for (ProduceDto produceDto : produceDtoList) {
            // 订单来源的排产无法删除
            if (ProduceSourceType.SALE_ORDER.equals(produceDto.getSourceType())) {
                throw new BaseException("当前排产来源于订单无法删除，若要修改信息请修改订单，订单号:【" + produceDto.getOrderNo() + "】");
            }
            int quantity = produceDto.getQuantity() - produceDto.getRemainingQuantity();
            if (ProduceState.FINISHED.equals(produceDto.getProduceState())) {
                throw new BaseException(ErpResultEnum.PRODUCE_COMPLETE_CAN_NOT_DELETE);
            }
            if (quantity > 0) {
                throw new BaseException(ErpResultEnum.PRODUCE_CAN_NOT_DELETE, quantity);
            }
        }
        produceRepository.deleteProduceByIds(ids);
        // 修改订单为未生产
        Set<Long> orderIds = produceDtoList.stream().map(ProduceDto::getOrderId).collect(Collectors.toSet());
        List<SaleOrderDto> saleOrderDtoList = saleOrderRepository.selectSaleOrderByIds(orderIds);
        for (SaleOrderDto saleOrderDto : saleOrderDtoList) {
            SaleOrderDto updateOrderDto = new SaleOrderDto();
            updateOrderDto.setId(saleOrderDto.getId());
            updateOrderDto.setOrderState(OrderState.UN_HANDLE);
            saleOrderRepository.updateById(updateOrderDto);
        }
    }

    /**
     * 暂停生产
     *
     * @param ids
     */
    @Transactional(rollbackFor = Exception.class)
    public void pauseProduce(Set<Long> ids) {
        for (Long id : ids) {
            ProduceDto produceDto = produceRepository.selectProduceById(id);
            if (Objects.isNull(produceDto)) {
                throw new BaseException(ErpResultEnum.PRODUCE_NOT_FOUND);
            }
            if (!ProduceState.IN_PRODUCTION.equals(produceDto.getProduceState())) {
                throw new BaseException(ErpResultEnum.PRODUCE_NOT_IN_PRODUCTION, produceDto.getProduceState().getDescription());
            }
            ProduceDto updateProduce = new ProduceDto();
            updateProduce.setId(produceDto.getId());
            updateProduce.setProduceState(ProduceState.SUSPEND);
            produceRepository.updateProduceById(updateProduce);
        }
    }

    /**
     * 恢复生产
     *
     * @param ids
     */
    @Transactional(rollbackFor = Exception.class)
    public void recoveryProduce(Set<Long> ids) {
        for (Long id : ids) {
            ProduceDto produceDto = produceRepository.selectProduceById(id);
            if (Objects.isNull(produceDto)) {
                throw new BaseException(ErpResultEnum.PRODUCE_NOT_FOUND);
            }
            if (!ProduceState.SUSPEND.equals(produceDto.getProduceState())) {
                throw new BaseException(ErpResultEnum.PRODUCE_NOT_SUSPEND, produceDto.getProduceState().getDescription());
            }
            ProduceDto updateProduce = new ProduceDto();
            updateProduce.setId(produceDto.getId());
            updateProduce.setProduceState(ProduceState.IN_PRODUCTION);
            produceRepository.updateProduceById(updateProduce);
        }
    }

    /**
     * 分页查询
     *
     * @param page
     * @param queryReq
     * @return
     */
    public Paging<ProduceResp> selectProducePage(Paging<ProduceQueryReq> page, ProduceQueryReq queryReq) {
        Paging<ProduceResp> produceRespPaging = PageUtil.pageCopy(produceRepository.selectProducePage(page, queryReq), ProduceResp.class);
        if (CollUtil.isEmpty(produceRespPaging.getRecords())) {
            return produceRespPaging;
        }
        Set<Long> productIds = produceRespPaging.getRecords().stream().map(ProduceResp::getProductId).collect(Collectors.toSet());
        Map<Long, ProductDto> productDtoMap = productRepository.selectProductByIds(productIds).stream().collect(Collectors.toMap(ProductDto::getId, v -> v));
        for (ProduceResp produceResp : produceRespPaging.getRecords()) {
            ProductDto productDto = productDtoMap.get(produceResp.getProductId());
            if (Objects.nonNull(productDto)) {
                produceResp.setProductInfo(BeanUtil.copyProperties(productDto, ProductResp.class));
            }
        }
        return produceRespPaging;
    }

    /**
     * 分页查询可以产量登记的生产中信息
     *
     * @param page
     * @param queryReq
     * @return
     */
    public Paging<ProduceResp> selectProduceRegistrationPage(Paging<ProduceQueryReq> page, ProduceQueryReq queryReq) {
        Paging<ProduceResp> produceRespPaging = PageUtil.pageCopy(produceRepository.selectProduceRegistrationPage(page, queryReq), ProduceResp.class);
        if (CollUtil.isEmpty(produceRespPaging.getRecords())) {
            return produceRespPaging;
        }
        Set<Long> productIds = produceRespPaging.getRecords().stream().map(ProduceResp::getProductId).collect(Collectors.toSet());
        Map<Long, ProductDto> productDtoMap = productRepository.selectProductByIds(productIds).stream().collect(Collectors.toMap(ProductDto::getId, v -> v));
        for (ProduceResp produceResp : produceRespPaging.getRecords()) {
            ProductDto productDto = productDtoMap.get(produceResp.getProductId());
            if (Objects.nonNull(productDto)) {
                produceResp.setProductInfo(BeanUtil.copyProperties(productDto, ProductResp.class));
            }
        }
        return produceRespPaging;
    }

    /**
     * @param queryReq
     * @return
     */
    public List<ProduceResp> selectProduceRegistrationList(ProduceQueryReq queryReq) {
        List<ProduceResp> produceRespList = BeanUtil.copyToList(produceRepository.selectProduceRegistrationList(queryReq), ProduceResp.class);
        Set<Long> productIds = produceRespList.stream().map(ProduceResp::getProductId).collect(Collectors.toSet());
        Map<Long, ProductDto> productDtoMap = productRepository.selectProductByIds(productIds).stream().collect(Collectors.toMap(ProductDto::getId, v -> v));
        for (ProduceResp produceResp : produceRespList) {
            ProductDto productDto = productDtoMap.get(produceResp.getProductId());
            if (Objects.nonNull(productDto)) {
                produceResp.setProductInfo(BeanUtil.copyProperties(productDto, ProductResp.class));
            }
        }
        return produceRespList;
    }

    /**
     * 通过id查询生产
     *
     * @param id
     * @return
     */
    public ProduceResp selectProduceById(Long id) {
        ProduceResp produceResp = BeanUtil.copyProperties(produceRepository.selectProduceById(id), ProduceResp.class);
        if (Objects.isNull(produceResp)) {
            return null;
        }
        ProductDto productDto = productRepository.selectProductById(produceResp.getProductId());
        if (Objects.nonNull(productDto)) {
            produceResp.setProductInfo(BeanUtil.copyProperties(productDto, ProductResp.class));
        }
        return produceResp;
    }

    /**
     * 生产
     */
    @Transactional(rollbackFor = Exception.class)
    public void produce(Collection<Long> saleOrderIds) {
        for (Long saleOrderId : saleOrderIds) {
            // 审批通过 生产
            SaleOrderDto saleOrderDto = saleOrderRepository.selectSaleOrderById(saleOrderId);
            if (Objects.isNull(saleOrderDto)) {
                throw new BaseException(ErpResultEnum.SALE_ORDER_NOT_FOUND);
            }
            if (!OrderState.UN_HANDLE.equals(saleOrderDto.getOrderState())) {
                throw new BaseException(ErpResultEnum.ORDER_STATE_CAN_NOT_PRODUCE, saleOrderDto.getOrderState().getDescription());
            }
            SaleOrderDto updateDto = new SaleOrderDto();
            updateDto.setId(saleOrderDto.getId());
            updateDto.setOrderState(OrderState.PROCESSING);
            saleOrderRepository.updateSaleOrderById(updateDto);

            ProduceDto produceDto = new ProduceDto();
            String seqNo = sequenceService.generateSeqNo(PubConstant.PRODUCTION_SEQ_KEY);
            produceDto.setProduceNo(seqNo);
            produceDto.setProduceDate(DateUtil.today());
            produceDto.setOrderId(saleOrderDto.getId());
            produceDto.setOrderNo(saleOrderDto.getOrderNo());
            produceDto.setProductId(saleOrderDto.getProductId());
            produceDto.setProductName(saleOrderDto.getProductName());
            produceDto.setCustomerId(saleOrderDto.getCustomerId());
            produceDto.setCustomerName(saleOrderDto.getCustomerName());
            produceDto.setQuantity(saleOrderDto.getQuantity());
            produceDto.setRemainingQuantity(saleOrderDto.getQuantity());
            produceDto.setPriority(saleOrderDto.getPriority());
            produceDto.setProduceState(ProduceState.IN_PRODUCTION);
            produceDto.setSourceType(ProduceSourceType.SALE_ORDER);
            produceDto.setProduceEndDate(null);
            produceDto.setRemark(saleOrderDto.getRemark());
            produceRepository.saveProduce(produceDto);
        }
    }

    /**
     * 查询订单状态的数量
     *
     * @return
     */
    public List<StateCountResp> selectProduceStateCount(ProduceQueryReq queryReq) {
        List<StateCountResp> countRespList = produceRepository.selectProduceStateCount(queryReq);
        Long totalCount = countRespList.stream().map(StateCountResp::getCount).reduce(0L, Long::sum);
        ArrayList<StateCountResp> resultList = Lists.newArrayList(new StateCountResp("-1", "全部", totalCount));
        Map<String, StateCountResp> stateCountRespMap = countRespList.stream().collect(Collectors.toMap(StateCountResp::getState, v -> v));
        List<StateCountResp> respList = Arrays.stream(ProduceState.values()).map(state -> {
            StateCountResp countResp = stateCountRespMap.get(state.getValue());
            if (Objects.isNull(countResp)) {
                countResp = new StateCountResp();
                countResp.setCount(0L);
            }
            countResp.setStateName(state.getDescription());
            countResp.setState(state.getValue());
            return countResp;
        }).toList();
        resultList.addAll(respList);
        return resultList;
    }

    /**
     * 通过订单Id查询生产信息
     *
     * @param orderId
     * @return
     */
    public ProduceResp selectProduceByOrderId(Long orderId) {
        ProduceDto produceDto = produceRepository.selectByOrderId(orderId);
        return BeanUtil.copyProperties(produceDto, ProduceResp.class);
    }

    /**
     * 根据排产编号查询
     *
     * @param produceNo
     * @return
     */
    public List<ProduceResp> selectByProduceNo(String produceNo) {
        return BeanUtil.copyToList(produceRepository.selectByProduceNoLike(produceNo), ProduceResp.class);
    }
}
